<template>
  <a-card :bordered="false">
    <search v-if="configs.searchConfig&&configs.searchConfig.length" ref="search" :config="searchConfig"
            @search="search" @getHeight="getHeight"/>
    <slot name="search"></slot>
    <div class="btns" v-if="configs.expands && configs.expands.length">
      <el-button v-for="(item,index) in configs.expands" :key="index" :type="index===0?'primary':'default'"
                 :icon="item.icon"
                 :disabled="item.disabled!==undefined && item.disabled"
                 @click="handleEmit(item,index)">{{ item.title }}
      </el-button>
    </div>

    <div class="page_table">
      <el-table
        fit
        :data="tableData"
        :header-cell-style="{'background':'rgb(249,249,249)','color':'#252525'}"
        style="width: 100%"
        row-key="id"
        v-loading="loading"
        max-height="580px"
        :tree-props="{children: configs.children||'children', hasChildren: configs.hasChildren}"
        ref="tableData"
        @row-click="radioChange"
        :highlight-current-row="!configs.hideSingle"
        @selection-change="handleSelectionChange">
        <!--      <el-table-column-->
        <!--        v-if = "!configs.hideSingle"-->
        <!--        fixed = "left"-->
        <!--        label = "选择"-->
        <!--        key = "radio1"-->
        <!--        width = "55">-->
        <!--        <template slot-scope = "scope">-->
        <!--          <el-radio v-model = "entity" :label = "scope.row"><i></i></el-radio>-->
        <!--        </template>-->
        <!--      </el-table-column>-->
        <el-table-column
          v-if="configs.hasChildren"
          fixed="left"
          class-name="has-children"
          key="hasChildren"
          width="60">
        </el-table-column>
        <el-table-column
          v-if="!configs.hideMultiple"
          fixed="left"
          type="selection"
          key="select1"
          width="55">
        </el-table-column>
        <el-table-column
          v-if="!configs.hideIndex"
          fixed="left"
          label="序号"
          key="index1"
          type="index"
          width="55">
          <template slot-scope="scope">
            <span>{{ (page.current - 1) * page.size + scope.$index + 1 }}</span>
          </template>
        </el-table-column>
        <template v-for="(item,index) in configs.column"
                  v-if="!(typeof item.hidden === 'function' ? item.hidden() : item.hidden)">
          <el-table-column
            v-if="!item.template && !item.render"
            ref="elTableColumn"
            :key="item.prop"
            :prop="item.prop"
            :label="item.label"
            :formatter="item.formatter ? formatter : null"
            :width="item.width||''"
            :fixed="item.fixed||false"
            show-overflow-tooltip>
          </el-table-column>
          <el-table-column
            :label="item.label"
            :width="item.width||''"
            :fixed="item.fixed||false"
            v-else-if="(item.render || !item.renderHeader) && !item.template"
          >

            <!--                    <template slot="header"-->
            <!--                              slot-scope="scope">-->
            <!--                        <lb-render v-if="item.renderHeader"-->
            <!--                                   :scope="scope"-->
            <!--                                   :render="item.renderHeader">-->
            <!--                        </lb-render>-->
            <!--                        <span v-else>{{ scope.column.label }}</span>-->
            <!--                    </template>-->
            <template slot-scope="scope">
              <lb-render :scope="scope"
                         :render="item.render"
              >
              </lb-render>
            </template>
          </el-table-column>
          <el-table-column
            v-else
            :key="item.prop"
            :prop="item.prop"
            :label="item.label"
            :formatter="item.formatter ? formatter : null"
            :width="item.width||''"
            :fixed="item.fixed||false"
            show-overflow-tooltip>
            <template slot-scope="scope">
              <!--            <el-popover-->
              <!--              placement = "right"-->
              <!--              title = "图片"-->
              <!--              trigger = "hover">-->
              <!--              <img :src = "scope.row[item.prop]" />-->
              <el-input-number slot="reference" v-if="item.template === 'inputNumber'"
                               v-model="scope.row[item.prop]"></el-input-number>
              <el-input slot="reference" v-else-if="item.template === 'input'"
                        v-model="scope.row[item.prop]" type="text"></el-input>
              <img v-else slot="reference" :src="scope.row[item.prop]"
                   style="max-height: 40px;max-width: 150px;margin-top: 5px;}">
              <!--            </el-popover>-->
            </template>
          </el-table-column>
        </template>
      </el-table>
    </div>

    <el-pagination
      v-if="!configs.noPage"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      background
      :current-page="page.current"
      :page-sizes="[20, 30, 50, 100]"
      :page-size="page.size"
      layout="total, sizes, prev, pager, next, jumper"
      :total="page.total">
    </el-pagination>
    <form-add-edit ref="formAdd" @ok="modalFormOk"></form-add-edit>
  </a-card>
</template>

<script>
import FormAddEdit from './form/FormAddEdit'
import clone from '@/utils/clone'
import lbRender from './lb-render'

export default {
  name: 'Crud',
  props: ['config', 'currentSelected', 'value', 'pageAppType'],
  components: { CrudSearch, FormAddEdit, lbRender },
  data() {
    return {
      self: this,
      visible: false, // 弹窗
      title: '', // 弹窗title
      entity: null, // 行数据
      configs: '', // 配置复制项
      searchParam: {}, // 搜索条件
      multipleSelection: [], // checkbox选中的行
      loading: false, // 表格loading
      tableData: [], // 表格数据
      page: {
        current: 1,
        size: this.config.size || 20,
        total: 0
      }, // 分页参数,
      expandsLoading: null
    }
  },
  watch: {
    tableData: {
      handler(tableData) {
        this.$emit('input', tableData)
      },
      deep: true
    },
    config: {
      handler(config) {
        if (this.value) {
          if (config && config.form) {
            Object.assign(config.form.form, this.value)
          } else {
            Object.assign(config, { form: { form: this.value } })
          }
        }
        this.configs = config
        if (this.configs.expands && this.configs.expands.length) {
          this.expandsLoading = new Array(this.configs.expands.length)
          this.expandsLoading.fill(false)
        }
      },
      deep: true
    }
  },
  mounted() {
    let config = clone(this.config)
    if (this.value) {
      if (config && config.form) {
        Object.assign(config.form.form, this.value)
      } else {
        Object.assign(config, { form: { form: this.value } })
      }
    }
    this.configs = config
    if (this.configs.expands && this.configs.expands.length) {
      this.expandsLoading = new Array(this.configs.expands.length)
      this.expandsLoading.fill(false)
    }
    this.getData() // 初始化表格数据
  },
  computed: {
    appType: {
      get() {
        return this.pageAppType || ''
      },
      set(v) {
        this.$emit('update:pageAppType', v)
      }
    }
  },
  methods: {
    formatter(row, column, cellValue, index) {
      const colIndex = this.configs.column.findIndex(({ label }) => label === column.label)
      if (column.property.search('operation') > -1 && this.configs.column[colIndex].formatter &&
        this.configs.column[colIndex].formatter
        instanceof Function) {
        return this.configs.column[colIndex].formatter(row, {
          updateRow: this.updateRow,
          deleteRow: this.deleteRow,
          exportRow: this.exportExcelRow,
          viewRow: this.viewRow,
          handleTableCellClick: this.handleTableCellClick,
          column, cellValue, index
        })
      } else {
        return this.configs.column[colIndex].formatter(row, {
          column, cellValue,
          index
        })
      }
    },
    /**
     * 查询--刷新表格数据
     * @params param 搜索参数
     * */
    search(param) {
      delete param.date
      this.searchParam = clone(param)
      if (Object.keys(this.searchParam).length && this.searchParam.hasOwnProperty('dates'))
      {
        delete this.searchParam.dates
        this.searchParam.startDate = param.dates[0]
        this.searchParam.endDate = param.dates[1]
      }
      this.getData(this.page.current, this.page.size, param)
    },
    /**
     * 请求表格数据
     * @params pageNo 当前页
     * @params pageSize 每页条数
     * @params search 搜索参数
     * */
    async getData(pageNo = 1, pageSize = 20, search = {}, callback) {
      if (typeof this.config.api !== 'function' && typeof this.config.api !== 'object') {
        return
      }
      let params_data = { ...this.configs.params, ...search }, configParams = {}
      console.log(params_data, 'params_data')
      for (let key in params_data) {
        if (typeof params_data[key] === 'function') {
          configParams[key] = params_data[key](this.configs.form.form)
          if (configParams[key] instanceof Promise) {
            configParams[key] = await configParams[key]
          }
        } else {
          configParams[key] = params_data[key]
        }
      }
      let params = this.configs.noPage ? configParams : { pageNo, pageSize, ...configParams }
      let before = true
      if (this.config.before !== undefined) {
        if (typeof this.config.before === 'function') {
          before = this.config.before(params)
          if (before instanceof Promise) {
            before = await before
          }
        } else {
          before = this.config.before
        }
      }
      if (!before) return
      this.loading = true
      if (typeof this.config.api === 'function') {
        console.log(params, 'params')
        const response = this.config.api(params)
        if (response instanceof Promise) {
          return response.then(res => {

            callback && callback(res)
            if (res && res.result) {
              this.$refs.tableData.clearSelection()
              let data = this.configs.noPage ? res.result : res.result.records
              if (this.configs.hasOwnProperty('dealData')) { // 若父类有处理数据的方法，就先处理数据再赋值
                data = this.configs.dealData(data)
              }
              this.tableData = data
              this.page = {
                current: res.result.current || 1,
                size: !this.configs.noPage ? this.page.size : 0,
                total: !this.configs.noPage ? res.result.total : data.length
              }
            } else {
              this.tableData.splice(0)
            }
            this.loading = false
            return res
          }).catch(res => {
            return res
          })
        } else {
          this.tableData = response
          this.loading = false
        }
      } else {
        this.tableData = this.config.api
        this.loading = false
      }
      return Promise.reject()
    },
    closeExpandsLoading(index) {

    },
    async handleEmit(item, index) {
      this.expandsLoading[index] = true
      if (item.beforeHandleClick && typeof item.beforeHandleClick === 'function') {
        const res = item.beforeHandleClick(this.multipleSelection)
        if (res && res.msg) {
          return this.$notify.error(res.msg)
        }
      }
      let funs = ['create', 'update', 'delete', 'view']
      if (funs.indexOf(item.fun) > -1) {
        this.expandsLoading[index] = false
        this[item.fun](item, index)
      } else {
        if (item.isRows) {
          if (!this.multipleSelection.length) {
            this.$notify({
              message: `选中数据才可以进行操作！`,
              type: 'warning'
            })
            return
          }
        }
        if (item.isRow) {
          if (!this.multipleSelection.length) {
            this.$notify({
              message: `选中数据才可以进行操作！`,
              type: 'warning'
            })
            return
          } else {
            if (this.multipleSelection.length > 1) {
              this.$notify({
                message: `只能对单条数据 进行操作！`,
                type: 'warning'
              })
              return
            }
          }
        }
        const row = item.isRow ? this.entity : item.isRows ? this.multipleSelection : null
        this.$emit(item.fun, row)
        this.expandsLoading[index] = false
      }
    },
    // 单选行事件
    radioChange(currentRow) {
      if (this.configs.hideSingle) {
      } else {
        if (this.configs.hideMultiple) {
          this.multipleSelection = [currentRow]
          this.entity = currentRow
        }
      }
    },
    // 多行事件
    handleSelectionChange(selection) {
      if (this.configs.hideMultiple) {
        console.log(selection)
      } else {
        this.multipleSelection = selection
        this.entity = selection[0]
      }
    },
    create(item, index) {
      this.appType = 'create'
      if (item.href) {
        this.expandsLoading[index] = false
        this.$router.push({ path: item.href })
      } else {
        let form = clone(this.config.form.form)
        delete this.configs.form.form
        this.configs.form.form = form
        this.title = `${item.title}${this.config.title}`
        this.visible = true
        this.expandsLoading[index] = false
      }

    },
    handleTableCellClick(fn, ...arg) {
      console.log(fn, ...arg)
      this.$emit(fn, ...arg)
    },
    view(item, index) {
      this.appType = 'view'
      this.expandsLoading[index] = false
      if (!this.multipleSelection.length) {
        this.$notify({
          message: `选中数据才可以进行操作！`,
          type: 'warning'
        })
        return
      } else {
        if (this.multipleSelection.length > 1) {
          this.$notify({
            message: `只能对单条数据 进行操作！`,
            type: 'warning'
          })
          return
        }
      }

      this.title = `${item.title}${this.config.title}`
      if (item.href) {
        this.expandsLoading[index] = false
        let query = {}
        if (item.params) {
          item.params.forEach(i => {
            query[i] = this.entity[i]
          })
        }
        this.$router.push({ path: item.href, query: Object.keys(query).length ? query : null })
      } else {
        this.configs.form.form = this.entity
        // Object.assign(this.form.form,this.entity)
        this.visible = true
      }
    },
    update(item, index) {
      this.appType = 'update'
      this.expandsLoading[index] = false
      this.title = `${item.title}${this.config.title}`
      if (!this.multipleSelection.length) {
        this.$notify({
          message: `选中数据才可以进行操作！`,
          type: 'warning'
        })
        return
      } else {
        if (this.multipleSelection.length > 1) {
          this.$notify({
            message: `只能对单条数据 进行操作！`,
            type: 'warning'
          })
          return
        }
      }

      if (item.href) {
        let query = {}
        if (item.params) {
          item.params.forEach(i => {
            query[i] = this.entity[i]
          })
        }
        this.$router.push({ path: item.href, query: Object.keys(query).length ? query : null })
      } else {
        delete this.configs.form.form
        this.configs.form.form = this.entity
        this.config.form.form = this.entity
        this.visible = true
      }
    },
    viewRow(row) {
      this.appType = 'view'
      this.title = `${this.config.title}`
      delete this.configs.form.form
      this.configs.form.form = row
      this.visible = true
    },
    updateRow(row) {
      this.appType = 'update'
      this.title = `${this.config.title}`
      delete this.configs.form.form
      this.configs.form.form = row
      this.visible = true
    },
    deleteRow(row, callback) {
      const { deleteApi } = this.config
      deleteApi({ id: row.id }).then(res => {
        if (res) {
          this.$notify({
            message: `删除成功！`,
            type: 'success'
          })
          this.entity = null

          this.getData()

          if (typeof callback === 'function') {
            callback(this.getData)
          }
        }
      })
    },
    exportExcelRow(row, ...arg) {
      try {

        let callback = null, params = null
        if (typeof arg.slice(-1)[0] === 'function') {
          callback = arg.pop()
        }
        const { exportApi } = this.config
        if (typeof arg.slice(0)[0] === 'object') {
          params = arg.shift()
        }
        exportApi(params || { id: row.id }).then(response => {
          if (response) {
            const disposition = response.headers['content-disposition']

            let fileName = disposition ? disposition.substring(disposition.toLocaleLowerCase().indexOf('filename=') + 9, disposition.length) : ''
            fileName = decodeURIComponent(fileName)
            // 去掉双引号
            fileName = fileName.replace(/\"/g, '')
            const content = response.data
            console.info('rep:', disposition)
            console.info('fileName:', fileName)
            // 创建a标签并点击， 即触发下载
            let url = window.URL.createObjectURL(new Blob([content]))
            let link = document.createElement('a')
            link.style.display = 'none'
            link.href = url
            link.setAttribute('download', fileName)
            //link.download = "测试下载文件.xls"
            // 模拟
            document.body.appendChild(link)
            link.click()
            // 释放URL 对象
            window.URL.revokeObjectURL(link.href)
            document.body.removeChild(link)

            if (typeof callback === 'function') {
              callback(this.getData)
            }
          }
        })
      } catch (e) {
        console.error(e)
      }
    },
    delete(item, index) {
      this.expandsLoading[index] = false
      if (!this.multipleSelection.length) {
        this.$notify({
          message: `选中数据才可以进行操作！`,
          type: 'warning'
        })
        return
      } else {
        if (this.multipleSelection.length > 1) {
          this.$notify({
            message: `只能对单条数据 进行操作！`,
            type: 'warning'
          })
          return
        }
      }
      console.log(this, this.multipleSelection)
      if (item.beforeAction && typeof item.beforeAction === 'function') {
        if (!item.beforeAction.apply(this, this.multipleSelection)) {
          return
        }
      }
      const { deleteApi } = this.config
      deleteApi({ id: this.entity.id }).then(res => {
        if (res) {
          this.$notify({
            message: `删除成功！`,
            type: 'success'
          })
          this.entity = null
          this.getData()
        }
      })
    },
    closeModal(form) {
      if (this.$attrs['close-modal'] !== undefined) {
        this.$emit('closeModal', form, function (extra) {
          form = extra
        })
      }
      if (form) {
        const { createApi, updateApi } = this.configs
        const api = form.id ? updateApi : createApi
        api(form).then(res => {
          if (res) {
            this.$notify({
              message: `${form.id ? '修改' : '新增'}成功！`,
              type: 'success'
            })
            this.visible = false
            this.entity = null
            this.getData()
          }
        })
      } else {
        this.visible = false
        // this.entity = null
      }
    },
    /**
     * 分页--切换每页页数
     * @params val 每页页数
     * */
    handleSizeChange(val) {
      this.getData(1, val, this.searchParam)
    },
    /**
     * 分页--切换当前页
     * @params val 当前页
     * */
    handleCurrentChange(val) {
      this.getData(val, this.page.size, this.searchParam)
    }
  }
}
</script>

<style rel="stylesheet/scss" lang="less">
.crud {
  .btns {
    margin-top: 10px;
    margin-bottom: 12px;

    .name {
      font-size: 14px;
      color: #606266;
      font-weight: 600;
      margin-right: 16px;
    }
  }

  .el-table--medium td, .el-table--medium th {
    padding: 0;
  }

  .el-pagination {
    text-align: right;
    padding: 24px 5px;
  }
}

.el-table--striped .el-table__body tr.el-table__row--striped.current-row td,
.el-table__body tr.current-row > td {
  background-color: rgba(255, 229, 163, 0.62);
}

.el-table--striped .el-table__body tr.hover-row.el-table__row--striped > td,
.el-table__body tr.hover-row > td {
  background-color: rgba(223, 223, 227, 0.67) !important;
}
</style>
